package com.semac.client.paginas.inscricao;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.semac.client.aplicacao.AplicacaoController;
import com.semac.client.aplicacao.Pagina;
import com.semac.client.aplicacao.PaginasController;
import com.semac.client.componentes.atividadestable.AtividadeCellTable;
import com.semac.client.componentes.atividadestable.AtividadeCellTableDeleteEvent;
import com.semac.client.componentes.atividadestable.AtividadeCellTableEventHandler;
import com.semac.client.componentes.atividadestable.AtividadeCellTableInscreveEvent;
import com.semac.client.componentes.atividadestable.AtividadeCellTableSelectEvent;
import com.semac.client.componentes.loading.Loading;
import com.semac.client.rpc.AtividadeRPCServices;
import com.semac.client.rpc.RPCCallBackWrapper;
import com.semac.client.rpc.SemanacRPCService;
import com.semac.shared.model.Atividade;
import com.semac.shared.model.Pessoa;
import com.semac.shared.model.SemanaAcademica;

public class InscricaoUI extends Composite implements Pagina, AtividadeCellTableEventHandler{
	
	
	private static InscricaoUIUiBinder uiBinder = GWT.create(InscricaoUIUiBinder.class);
	@UiField Label nomeSemacLabel;
	@UiField(provided=false) AtividadeCellTable atividadesCellTable = new AtividadeCellTable();
	@UiField(provided=false) AtividadeCellTable inscricaoCellTable = new AtividadeCellTable();
	@UiField Label descAtividSelecLabel;
	@UiField Label nenhumInscricaoLabel;
	@UiField Label nenhumaAtividadeLabel;
	@UiField Button btnSalvarModificacoes;
	@UiField Loading loading;
	@UiField VerticalPanel tabelasAtividadesPanel;
	@UiField Label inscricaoDesabiltadaLabel;
	@UiField Label nomeSemanaAcademicaLabel;
	
	private ArrayList<Atividade> listaDeInscricoes = new ArrayList<Atividade>();
	private ArrayList<Atividade> listaDeAtividades = new ArrayList<Atividade>();
	private SemanaAcademica semanaAtiva = null;
	
	

	interface InscricaoUIUiBinder extends UiBinder<Widget, InscricaoUI> {
	}

	
	
	
	
	public InscricaoUI() {
		initWidget(uiBinder.createAndBindUi(this));
		atividadesCellTable.setRowData(new ArrayList<Atividade>());
		inscricaoCellTable.setRowData(new ArrayList<Atividade>());
		
		this.setSalvarEnable(false);
		this.addAtividadesHandler();
		
		this.pegaSemanaAtiva();
		
		//this.atualizaAtividadesDaSemana();
		
	}

	
	
	
	private void pegaSemanaAtiva() {
		SemanacRPCService.Util.getInstance().pegaSemanaAcademicaAtiva(new RPCCallBackWrapper<SemanaAcademica>(this.loading,true) {

			@Override
			public void gotResult(SemanaAcademica result) {
				semanaAtiva = result;
				if (semanaAtiva == null){
					//nao ha semana ativa, portanto, mostrar label de semana nao ativa
					nomeSemanaAcademicaLabel.setText("Nenhuma semana acadêmica ativa no momento.");
					tabelasAtividadesPanel.setVisible(false);
				}else{
					tabelasAtividadesPanel.setVisible(true);
					DateTimeFormat formatter = DateTimeFormat.getFormat("dd/MM/yyyy");
					//Mostrar nome da semana academica ativa no momento.
					nomeSemanaAcademicaLabel.setText(result.getDescricao());
					
					//mostra as tabelas
					//se ainda é muito cedo para se inscrever nas atividades, desabilita edicao de inscricao
					if (semanaAtiva.getInicioInscricao().after(new Date()) || new Date().after(semanaAtiva.getFimInscricao()) ){
						atividadesCellTable.configuraPermissoes(false, false);
						inscricaoCellTable.configuraPermissoes(false, false);
						inscricaoDesabiltadaLabel.setText("Inscrição não disponível para o momento. " +
														  "Período de inscrição vai do dia " + formatter.format(semanaAtiva.getInicioInscricao()) + " ao dia " +
														  formatter.format(semanaAtiva.getFimInscricao()));
					}else{
						atividadesCellTable.configuraPermissoes(true,true);
						inscricaoCellTable.configuraPermissoes(true,false);
						btnSalvarModificacoes.setVisible(true);
					}
					
					//mostra as tabelas
					tabelasAtividadesPanel.setVisible(true);
					
					atualizaAtividadesDaSemana();
				}
				
			}
		});
	}




	private void addAtividadesHandler() {
		this.atividadesCellTable.addAtividadeInscreveHandler(this);
		this.inscricaoCellTable.addAtividadeDeleteHandler(this);
		this.atividadesCellTable.addAtividadeSelecionadaHandler(this);
		this.inscricaoCellTable.addAtividadeSelecionadaHandler(this);
	}




	private void atualizaInscricoesDoAluno() {
		AtividadeRPCServices.Util.getInstance().pegaInscricoesAluno(new RPCCallBackWrapper<ArrayList<Atividade>>(this.loading,true) {
			@Override
			public void gotResult(ArrayList<Atividade> result) {			
				listaDeInscricoes.clear();
				listaDeInscricoes.addAll(result);
				refreshListas();
				setSalvarEnable(false);
			}
		});
	}
	


	private void atualizaAtividadesDaSemana() {
		if (semanaAtiva != null){
			Atividade ativ = new Atividade();
			ativ.setCodSemac(semanaAtiva.getCodSemana());
			AtividadeRPCServices.Util.getInstance().selecionaAtividadesLike(ativ,true,new RPCCallBackWrapper<ArrayList<Atividade>>(this.loading,true) {
				@Override
				public void gotResult(ArrayList<Atividade> result) {				
					listaDeAtividades.clear();
					listaDeAtividades.addAll(result);
					atualizaInscricoesDoAluno();
				}
			});
		}
	}


	private void refreshListas() {
		this.loading.setVisible(true);
		
		ArrayList<Atividade> listaDosExcluidos = new ArrayList<Atividade>();
		
		//retira da lista de atividades as atividades da lista de inscricao do aluno.
		//NOTA: não da pra excluir direto, aqui no for, pois senao o loop da erro ....
		for (Atividade atividade : this.listaDeAtividades) {
			for (Atividade atividadeInscrita : this.listaDeInscricoes) {
				if (atividade.equals(atividadeInscrita))
					listaDosExcluidos.add(atividade);
			}
		}
		
		
		//deleta da lista de atividades as atividades que o aluno já está inscrito (para nao termos duplicatas de atividades
		//nas listas)
		for (Atividade atividade : listaDosExcluidos) {
			this.listaDeAtividades.remove(atividade);
		}
		

		//lista das atividades
		nenhumaAtividadeLabel.setVisible((listaDeAtividades == null || listaDeAtividades.size() == 0));
		atividadesCellTable.setRowData(listaDeAtividades);

		//lista das inscricoes
		nenhumInscricaoLabel.setVisible((listaDeInscricoes == null || listaDeInscricoes.size() == 0));
		inscricaoCellTable.setRowData(listaDeInscricoes);

		setSalvarEnable(true);
		this.loading.setVisible(false);

	}




	private void setSalvarEnable(boolean enable){
		this.btnSalvarModificacoes.setEnabled(enable);
		if (enable)
			this.btnSalvarModificacoes.setText("Salvar modificações");
		else
			this.btnSalvarModificacoes.setText("Modificações salvas");
	}
	




	@Override
	public void onAtividadeSelect(AtividadeCellTableSelectEvent event) {
		if (event.getSource() == this.atividadesCellTable)
			this.inscricaoCellTable.cancelSelection();
		else
			this.atividadesCellTable.cancelSelection();
		
		this.descAtividSelecLabel.setText(event.getAtividade().getDescricao());
	}




	@Override
	public void onAtividadeDelete(AtividadeCellTableDeleteEvent event) {
		if (event.getSource() == this.inscricaoCellTable){
			this.listaDeInscricoes.remove(event.getAtividade());
			this.listaDeAtividades.add(event.getAtividade());
			this.refreshListas();
		}			
	}

	
	
	
	@Override
	public void onAtividadeInscreve(AtividadeCellTableInscreveEvent event) {
		//ve se o evento partiu da lista de atividades certa
		if (event.getSource() != this.atividadesCellTable)
			return; //retorna se nao  eh
		
		
		/*percorre a lista pra ver se nao tem colisao de horarios
		 * a ideia é a seguinte, são tres casos:
		 * Se a atividade nova tem a data de inicio maior que a data de inicio da segunda, 
		 * mas menor que a data de fim da segunda 
		 * OU
		 * Se a atividade nova tem a data de termino maior q a data de inicio da segunda
		 * e menor que a data de termino da segunda
		 * OU
		 * se a data inicial da primeira é menor que a inicial da segunda e a data final da primeira
		 * é maior que a final da segunda,
		 * HÁ colisao.
		 * Ignora o adicionamento e dá um warning de que não pode ser inscrito.
		 */		
		Atividade novaAtividade = event.getAtividade();
		for (Atividade atividade : this.listaDeInscricoes) {
			
			if ((novaAtividade.getDiaDaAtividade().compareTo(atividade.getDiaDaAtividade()) >= 0 && 
					novaAtividade.getDiaDaAtividade().compareTo(atividade.getFimDaAtividade()) < 0) || 

					(novaAtividade.getFimDaAtividade().compareTo(atividade.getDiaDaAtividade()) > 0 && 
							novaAtividade.getFimDaAtividade().compareTo(atividade.getFimDaAtividade()) <= 0) ||

							(novaAtividade.getDiaDaAtividade().compareTo(atividade.getDiaDaAtividade()) <= 0 &&
									novaAtividade.getFimDaAtividade().compareTo(atividade.getFimDaAtividade()) >= 0)){
				//da aviso de falha e retorna
				Window.alert("Atenção! Não é possível inserir esta atividade pois há colisão de horários.");
				return;
			}			
		}
		
		
		//testa agora para ver se a pessoa logada nao esta tentando se inscrever numa atividade em que é tutora.
		//se for tutora, nao permite.
		for (Pessoa ministrante : event.getAtividade().getMinistrantes()) {
			if (ministrante.equals(AplicacaoController.getPessoaLogada())){
				Window.alert("Atenção! Você não pode se inscrever em uma atividade em que é ministrante.");
				return;
			}				
		}
		
		
		//senao, adiciona na boa, e já habilita o botao para salvar.
		this.listaDeAtividades.remove(event.getAtividade());
		this.listaDeInscricoes.add(event.getAtividade());
		this.refreshListas();
	}
	
	
	
	@UiHandler("btnSalvarModificacoes")
	void onBtnSalvarModificacoesClick(ClickEvent event) {
		
		AsyncCallback<Void> callBack = new AsyncCallback<Void>() {
			
			@Override
			public void onSuccess(Void result) {
				Window.alert("Inscrição realizada com sucesso");
				loading.setVisible(false);
				setSalvarEnable(false);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(caught.getLocalizedMessage());
				loading.setVisible(false);
				setSalvarEnable(true);
			}
		};
		
		this.loading.setVisible(true);
		this.btnSalvarModificacoes.setText("Salvando....");
		this.btnSalvarModificacoes.setEnabled(false);
		
		AtividadeRPCServices.Util.getInstance().inscreveAluno(this.listaDeInscricoes, 
											 callBack);
		
		
	}
	
	
	
	

	@Override
	public String getValorHistoryToken() {
		return PaginasController.INSCRICAO;
	}




	@Override
	public Widget getView() {
		return this;
	}

}
